/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure.neo4j;

import java.io.File;
import java.net.URI;
import java.time.Duration;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * Neo4j 的配置属性。
 *
 * @author Michael J. Simons
 * @author Stephane Nicoll
 * @since 2.4.0
 */
@ConfigurationProperties(prefix = "spring.neo4j")
public class Neo4jProperties {

	/**
	 * 驱动使用的 URI。
	 */
	private URI uri;

	/**
	 * 从连接池借用连接的超时时间。
	 */
	private Duration connectionTimeout = Duration.ofSeconds(30);

	/**
	 * 事务允许重试的最长时间。
	 */
	private Duration maxTransactionRetryTime = Duration.ofSeconds(30);

	private final Authentication authentication = new Authentication();

	private final Pool pool = new Pool();

	private final Security security = new Security();

	public URI getUri() {
		return this.uri;
	}

	public void setUri(URI uri) {
		this.uri = uri;
	}

	public Duration getConnectionTimeout() {
		return this.connectionTimeout;
	}

	public void setConnectionTimeout(Duration connectionTimeout) {
		this.connectionTimeout = connectionTimeout;
	}

	public Duration getMaxTransactionRetryTime() {
		return this.maxTransactionRetryTime;
	}

	public void setMaxTransactionRetryTime(Duration maxTransactionRetryTime) {
		this.maxTransactionRetryTime = maxTransactionRetryTime;
	}

	public Authentication getAuthentication() {
		return this.authentication;
	}

	public Pool getPool() {
		return this.pool;
	}

	public Security getSecurity() {
		return this.security;
	}

	public static class Authentication {

		/**
		 * 服务器登录用户名。
		 */
		private String username;

		/**
		 * 服务器登录密码。
		 */
		private String password;

		/**
		 * 连接所使用的域（Realm）。
		 */
		private String realm;

		/**
		 * 用于连接数据库的 Kerberos 票据。与指定用户名互斥。
		 */
		private String kerberosTicket;

		public String getUsername() {
			return this.username;
		}

		public void setUsername(String username) {
			this.username = username;
		}

		public String getPassword() {
			return this.password;
		}

		public void setPassword(String password) {
			this.password = password;
		}

		public String getRealm() {
			return this.realm;
		}

		public void setRealm(String realm) {
			this.realm = realm;
		}

		public String getKerberosTicket() {
			return this.kerberosTicket;
		}

		public void setKerberosTicket(String kerberosTicket) {
			this.kerberosTicket = kerberosTicket;
		}

	}

	public static class Pool {

		/**
		 * 是否启用指标监控。
		 */
		private boolean metricsEnabled = false;

		/**
		 * 是否记录泄漏的会话日志。
		 */
		private boolean logLeakedSessions = false;

		/**
		 * 连接池中针对单个数据库的最大连接数。
		 */
		private int maxConnectionPoolSize = 100;

		/**
		 * 在连接池中空闲时间超过该阈值的连接，在再次使用前将进行测试。
		 */
		private Duration idleTimeBeforeConnectionTest;

		/**
		 * 连接池中超过该生命周期的连接将被关闭并移除。
		 */
		private Duration maxConnectionLifetime = Duration.ofHours(1);

		/**
		 * 新连接的获取尝试将在配置的超时时间内进行。
		 */
		private Duration connectionAcquisitionTimeout = Duration.ofSeconds(60);

		public boolean isLogLeakedSessions() {
			return this.logLeakedSessions;
		}

		public void setLogLeakedSessions(boolean logLeakedSessions) {
			this.logLeakedSessions = logLeakedSessions;
		}

		public int getMaxConnectionPoolSize() {
			return this.maxConnectionPoolSize;
		}

		public void setMaxConnectionPoolSize(int maxConnectionPoolSize) {
			this.maxConnectionPoolSize = maxConnectionPoolSize;
		}

		public Duration getIdleTimeBeforeConnectionTest() {
			return this.idleTimeBeforeConnectionTest;
		}

		public void setIdleTimeBeforeConnectionTest(Duration idleTimeBeforeConnectionTest) {
			this.idleTimeBeforeConnectionTest = idleTimeBeforeConnectionTest;
		}

		public Duration getMaxConnectionLifetime() {
			return this.maxConnectionLifetime;
		}

		public void setMaxConnectionLifetime(Duration maxConnectionLifetime) {
			this.maxConnectionLifetime = maxConnectionLifetime;
		}

		public Duration getConnectionAcquisitionTimeout() {
			return this.connectionAcquisitionTimeout;
		}

		public void setConnectionAcquisitionTimeout(Duration connectionAcquisitionTimeout) {
			this.connectionAcquisitionTimeout = connectionAcquisitionTimeout;
		}

		public boolean isMetricsEnabled() {
			return this.metricsEnabled;
		}

		public void setMetricsEnabled(boolean metricsEnabled) {
			this.metricsEnabled = metricsEnabled;
		}

	}

	public static class Security {

		/**
		 * 驱动是否应使用加密流量。
		 */
		private boolean encrypted = false;

		/**
		 * 使用的信任策略。
		 */
		private TrustStrategy trustStrategy = TrustStrategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES;

		/**
		 * 存放受信任证书的文件路径。
		 */
		private File certFile;

		/**
		 * 是否需要进行主机名验证。
		 */
		private boolean hostnameVerificationEnabled = true;

		public boolean isEncrypted() {
			return this.encrypted;
		}

		public void setEncrypted(boolean encrypted) {
			this.encrypted = encrypted;
		}

		public TrustStrategy getTrustStrategy() {
			return this.trustStrategy;
		}

		public void setTrustStrategy(TrustStrategy trustStrategy) {
			this.trustStrategy = trustStrategy;
		}

		public File getCertFile() {
			return this.certFile;
		}

		public void setCertFile(File certFile) {
			this.certFile = certFile;
		}

		public boolean isHostnameVerificationEnabled() {
			return this.hostnameVerificationEnabled;
		}

		public void setHostnameVerificationEnabled(boolean hostnameVerificationEnabled) {
			this.hostnameVerificationEnabled = hostnameVerificationEnabled;
		}

		public enum TrustStrategy {

			/**
			 * 信任所有证书。
			 */
			TRUST_ALL_CERTIFICATES,

			/**
			 * 信任由受信任证书签署的证书。
			 */
			TRUST_CUSTOM_CA_SIGNED_CERTIFICATES,

			/**
			 * 信任可以通过本地系统证书库验证的证书。
			 */
			TRUST_SYSTEM_CA_SIGNED_CERTIFICATES

		}

	}

}
